/*
    SUSAN® - Sole of Unix Save ANything

   Copyright (C) 2004-2007 Hechzh Property
   Copyright (C) 2016-2016 Skyatlas Co. CN

   
*/
/*
 * Written by Preben 'Peppe' Guldberg, December MMIV
 */
/**
 * @file
 * Implement routines to determine file system types.
 */

#include "include/susan.h"
#include "find.h"
#include "findlib/fstype.h"
#include "lib/util.h"

/**
 * These functions should be implemented for each OS
 *
 * bool fstype(const char *fname, char *fs, int fslen);
 */
#if defined(HAVE_DARWIN_OS) || defined(HAVE_FREEBSD_OS) || \
    defined(HAVE_OPENBSD_OS)

#include <sys/param.h>
#include <sys/mount.h>

bool fstype(const char* fname, char* fs, int fslen)
{
  struct statfs st;

  if (statfs(fname, &st) == 0) {
    bstrncpy(fs, st.f_fstypename, fslen);
    return true;
  }

  Dmsg1(50, "statfs() failed for \"%s\"\n", fname);
  return false;
}

#elif defined(HAVE_NETBSD_OS)
#include <sys/param.h>
#include <sys/mount.h>
#ifdef HAVE_SYS_STATVFS_H
#include <sys/statvfs.h>
#else
#define statvfs statfs
#endif

bool fstype(const char* fname, char* fs, int fslen)
{
  struct statvfs st;

  if (statvfs(fname, &st) == 0) {
    bstrncpy(fs, st.f_fstypename, fslen);
    return true;
  }

  Dmsg1(50, "statfs() failed for \"%s\"\n", fname);
  return false;
}

#elif defined(HAVE_HPUX_OS) || defined(HAVE_IRIX_OS)

#include <sys/types.h>
#include <sys/statvfs.h>

bool fstype(const char* fname, char* fs, int fslen)
{
  struct statvfs st;

  if (statvfs(fname, &st) == 0) {
    bstrncpy(fs, st.f_basetype, fslen);
    return true;
  }

  Dmsg1(50, "statfs() failed for \"%s\"\n", fname);
  return false;
}

#elif defined(HAVE_LINUX_OS) || defined(HAVE_OSF1_OS)

#include <sys/stat.h>
#include "lib/mntent_cache.h"

bool fstype(const char* fname, char* fs, int fslen)
{
  struct stat st;
  mntent_cache_entry_t* mce;

  if (lstat(fname, &st) == 0) {
    if ((mce = find_mntent_mapping(st.st_dev)) != NULL) {
      bstrncpy(fs, mce->fstype, fslen);
      ReleaseMntentMapping(mce);
      return true;
    }
    return false;
  }

  Dmsg1(50, "lstat() failed for \"%s\"\n", fname);
  return false;
}

#elif defined(HAVE_SUN_OS)

#include <sys/types.h>
#include <sys/stat.h>

bool fstype(const char* fname, char* fs, int fslen)
{
  struct stat st;

  if (lstat(fname, &st) == 0) {
    bstrncpy(fs, st.st_fstype, fslen);
    return true;
  }

  Dmsg1(50, "lstat() failed for \"%s\"\n", fname);
  return false;
}

#elif defined(HAVE_WIN32)
/* Windows */

bool fstype(const char* fname, char* fs, int fslen)
{
  DWORD componentlength;
  DWORD fsflags;
  CHAR rootpath[4];
  UINT oldmode;
  BOOL result;

  /* Copy Drive Letter, colon, and backslash to rootpath */
  bstrncpy(rootpath, fname, sizeof(rootpath));

  /* We don't want any popups if there isn't any media in the drive */
  oldmode = SetErrorMode(SEM_FAILCRITICALERRORS);

  result = GetVolumeInformation(rootpath, NULL, 0, NULL, &componentlength,
                                &fsflags, fs, fslen);

  SetErrorMode(oldmode);

  if (result) {
    /* Windows returns NTFS, FAT, etc.  Make it lowercase to be consistent with
     * other OSes */
    lcase(fs);
  } else {
    Dmsg2(10, "GetVolumeInformation() failed for \"%s\", Error = %d.\n",
          rootpath, GetLastError());
  }

  return result != 0;
}

/* Windows */

#else /* No recognised OS */

bool fstype(const char* fname, char* fs, int fslen)
{
  Dmsg0(10, "!!! fstype() not implemented for this OS. !!!\n");
  return false;
}
#endif

/**
 * Compare function build on top of fstype, OS independent.
 *
 * bool FstypeEquals(const char *fname, const char *fstypename);
 */
bool FstypeEquals(const char* fname, const char* fstypename)
{
  char fs_typename[128];

  if (fstype(fname, fs_typename, sizeof(fs_typename))) {
    return bstrcmp(fs_typename, fstypename);
  }

  return false;
}
